package controller

import (
	"errors"
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/blog/initialization"
	"github.com/blog/internal/component"
	"github.com/blog/internal/constants"
	"github.com/blog/internal/container"
	"github.com/blog/internal/response"
	"github.com/blog/model"
	"github.com/blog/model/requestModel"
	"github.com/blog/model/responseModel"
	"github.com/blog/utils"
	"github.com/gin-gonic/gin"
	"github.com/mojocn/base64Captcha"
	"go.uber.org/zap"
)

type UserController struct {
	Container container.Container
}

var captchaStore = sync.Map{}

func GenCaptcha(ctx *gin.Context) (captchaId string, image64 *string, err error) {
	driver := base64Captcha.NewDriverDigit(80, 240, 4, 0.5, 8)
	captcha := base64Captcha.NewCaptcha(driver, base64Captcha.DefaultMemStore)
	id, b64s, answer, err := captcha.Generate()
	if err != nil {
		return "", nil, err
	}
	zap.S().Infof("验证码Id:", id, " 码：", answer)
	captchaStore.Store(id, answer)
	return id, &b64s, nil
}

/*
*
登入
*/
func UserLogin(vo *requestModel.UserLoginRequestModel) (*responseModel.LoginResponseModel, error) {
	user, err := SelectByUserName(vo.Username)
	if err != nil {
		return nil, err
	}
	if user.State != 1 {
		return nil, errors.New("用户被禁止的登入")
	}
	pwd := utils.Md5String(vo.Password)
	if strings.Compare(user.Password, pwd) != 0 {
		return nil, errors.New("账号或密码错误")
	}
	UpdateUserLoginTime(user.Id)
	return genLoginAuth(user.Id, user.UserName), nil
}

/*
*
更新登入时间
*/
func UpdateUserLoginTime(id int) (bool, error) {
	var t = time.Now()
	r := initialization.Container.GetGormDb().Model(&model.Users{}).Where("id =?", id).Update("last_login", t)
	if r.Error != nil {
		return false, r.Error
	}
	return true, nil
}

/*
*
验证
*/
func VerifyCaptcha(captchaId string, code string) bool {
	if len(captchaId) <= 0 || len(code) <= 0 {
		return false
	}
	//验证码id获取code
	answer, b := captchaStore.Load(captchaId)

	if !b {
		return false
	}
	if code != answer.(string) {
		return false
	}
	captchaStore.Delete(captchaId)
	return true
}

/*
*
根据用户名查询用户
*/
func SelectByUserName(value string) (*model.Users, error) {
	var user model.Users
	r := initialization.Container.GetGormDb().Model(&model.Users{}).Where(&model.Users{UserName: value, State: 1}).First(&user)
	if r.Error != nil {
		return nil, r.Error
	}
	return &user, nil
}

/*
*
保存用户
*/
func SaveNew(username string, email string, password string) (int, error) {
	t := time.Now()
	bean := model.Users{UserName: username, Email: email, Password: password, State: 1, CreateTime: &t, LastLogin: &t}
	r := initialization.Container.GetGormDb().Create(&bean)
	if r.Error != nil {
		return 0, r.Error
	}
	// 返回新插入记录的ID，而不是影响的行数
	return bean.Id, nil
}

func genLoginAuth(id int, name string) *responseModel.LoginResponseModel {
	token, err := component.GetJwtInstance().GenToken(id, name)
	if err != nil {
		fmt.Println("genLoginAuth", err.Error())
		panic(err)
	}
	return &responseModel.LoginResponseModel{Token: token, UserName: name}
}

/*
**
用户名是否存在
*/
func ExistByUserName(username string) (bool, error) {
	count := int64(0)
	initialization.Container.GetGormDb().Model(&model.Users{}).Where(&model.Users{UserName: username, State: 1}).Count(&count)
	return count > 0, nil
}

func RegisterUser(userRegister *model.UserRegisterModel) (*responseModel.LoginResponseModel, error) {
	b, err := ExistByUserName(userRegister.Username)
	if err != nil {
		fmt.Println("RegisterUser", err.Error())
		return nil, err
	}
	if b {
		fmt.Println("RegisterUser", "该用户名已存在，请更换")
		return nil, errors.New("该用户名已存在，请更换")
	}
	pwd := utils.Md5String(userRegister.Password)
	id, err := SaveNew(userRegister.Username, userRegister.Email, pwd)

	if err != nil {
		fmt.Println("RegisterUser", err.Error())
		return nil, err
	}
	return genLoginAuth(id, userRegister.Username), nil

}

/*
*
根据ID查询
*/
func SelectById(id int) (*model.Users, error) {
	var user model.Users
	r := initialization.Container.GetGormDb().Model(&model.Users{}).Where(&model.Users{Id: id}).First(&user)
	if r.Error != nil {
		return nil, r.Error
	}
	return &user, nil
}

/*
*
获取用户信息
*/
func GetUserInfo(id int) (*model.Users, error) {
	if id <= 0 {
		return nil, errors.New("error")
	}
	user, err := SelectById(id)
	if err != nil {
		return nil, errors.New("该用户信息不存在")
	}
	return user, nil
}

/*
生成验证码 /v1
*/
func (uc *UserController) Captcha(ctx *gin.Context) {
	id, bs64img, err := GenCaptcha(ctx)
	if err != nil {
		response.Error(ctx, constants.ResponseError, "验证码生成失败")
		return
	}
	var captchaDto = responseModel.GenCaptchaModel{CaptchaId: id, Image64: *bs64img}
	response.Success(ctx, captchaDto)
}

/*
**
注册API
*/
func (uc *UserController) Register(ctx *gin.Context) {
	fmt.Println("开始注册流程")
	var userRegisterModel model.UserRegisterModel
	err := ctx.ShouldBindJSON(&userRegisterModel)
	if err != nil {
		response.Error(ctx, constants.ResponseError, err.Error())
		fmt.Println("注册流程错误", err.Error())
		return
	}
	vSuccess := VerifyCaptcha(userRegisterModel.CaptchaId, userRegisterModel.Code)
	if !vSuccess {
		response.Error(ctx, constants.ResponseError, "验证码错误！")
		fmt.Println("验证码错误", err.Error())
		return
	}
	result, err := RegisterUser(&userRegisterModel)
	if err != nil {
		fmt.Println("注册错误", err.Error())
		response.Error(ctx, constants.ResponseError, err.Error())
		return
	}

	response.Success(ctx, result)
}

/*
**
登入api
*/
func (uc *UserController) Login(ctx *gin.Context) {
	fmt.Println("开始登入流程")
	var vo requestModel.UserLoginRequestModel
	err := ctx.ShouldBindJSON(&vo)
	if err != nil {
		response.Error(ctx, constants.ResponseError, "参数异常")
		return
	}
	vSuccess := VerifyCaptcha(vo.CaptchaId, vo.Code)
	if !vSuccess {
		response.Error(ctx, constants.ResponseError, "验证码错误！")
		return
	}
	user, err := UserLogin(&vo)
	if err != nil {
		response.Error(ctx, constants.ResponseError, err.Error())
		return
	}
	response.Success(ctx, user)
}

/*
*
获取用户信息
*/
func (uc *UserController) UserInfo(ctx *gin.Context) {
	userId := ctx.GetInt(constants.UserIdKey)
	if userId <= 0 {
		response.Error(ctx, constants.ResponseError, "请登入后操作")
		return
	}
	info, err := GetUserInfo(userId)
	if err != nil {
		response.Error(ctx, constants.ResponseError, err.Error())
		return
	}
	info.Password = ""
	response.Success(ctx, info)
}
